package com.blb.day06.service.impl;

import com.baomidou.mybatisplus.extension.plugins.pagination.Page;
import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
import com.blb.day06.entity.Student;
import com.blb.day06.mapper.StudentMapper;
import com.blb.day06.service.StudentService;
import org.redisson.api.RBloomFilter;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.cache.annotation.CacheEvict;
import org.springframework.cache.annotation.CachePut;
import org.springframework.cache.annotation.Cacheable;
import org.springframework.cache.annotation.Caching;
import org.springframework.data.redis.core.RedisTemplate;
import org.springframework.data.redis.core.ValueOperations;
import org.springframework.stereotype.Service;

import java.util.concurrent.TimeUnit;

@Service
public class StudentServiceImpl extends ServiceImpl<StudentMapper, Student> implements StudentService {

    public static final String PREFIX = "Student-";

    @Autowired
    private StudentMapper studentMapper;

    @Autowired
    private RedisTemplate<String,Object> redisTemplate;

    @Cacheable(cacheNames = "Student-Page",key = "T(String).valueOf(#current)")
    @Override
    public Page<Student> getStudentPage(Long current, Long size) {
        return studentMapper.selectStudentPage(new Page<>(current,size));
    }

//    @Cacheable(cacheNames = "Student",key = "T(String).valueOf(#id)")
//    @Override
//    public Student getStudentById(Long id) {
//        return studentMapper.selectById(id);
//    }

//    @CacheEvict(cacheNames = "Student",key = "T(String).valueOf(#id)")
    //使用组合注解，删除一个学生时，将所有分页缓存删掉
    @Caching(
            evict = {@CacheEvict(cacheNames = "Student", key = "T(String).valueOf(#id)"),
                    @CacheEvict(cacheNames = "Student-Page", allEntries = true)
            }
    )
    @Override
    public void removeStudentById(Long id) {
        studentMapper.deleteById(id);
    }

//    @CachePut(cacheNames = "Student",key = "T(String).valueOf(#student.stuId)")
    @Caching(
            put = @CachePut(cacheNames = "Student",key = "T(String).valueOf(#student.stuId)"),
            evict = @CacheEvict(cacheNames = "Student-Page", allEntries = true)
    )
    @Override
    public Student updateStudentById(Student student) {
        studentMapper.updateById(student);
        return student;
    }

//    @CachePut(cacheNames = "Student",key = "T(String).valueOf(#student.stuId)")
    @Caching(
            put = @CachePut(cacheNames = "Student",key = "T(String).valueOf(#student.stuId)"),
            evict = @CacheEvict(cacheNames = "Student-Page", allEntries = true)
    )
    @Override
    public Student addStudent(Student student) {
        studentMapper.insert(student);
        return student;
    }

    @Autowired
    private RBloomFilter<String> rBloomFilter;

    @Override
    public Student getStudentById(Long id) {
        //获得字符串操作对象
        ValueOperations<String, Object> ops = redisTemplate.opsForValue();
        //先查询Redis
        Student stu = (Student) ops.get(PREFIX + id);
        if(stu == null) {
            synchronized (this) {
                System.out.println("进入了同步锁");
                //先查询Redis
                stu = (Student) ops.get(PREFIX + id);
                //如果Redis缓存存在数据，就直接返回
                if (stu != null) {
                    System.out.println("Redis查到，返回" + stu);
                    return stu;
                }
                //使用布隆过滤器判断数据库中是否存在该id
                if(rBloomFilter.contains(String.valueOf(id))) {
                    //如果Redis没有查到数据，就查询MySQL
                    stu = studentMapper.selectById(id);
                    //MySQL查到数据，就保存到Redis
                    if (stu != null) {
                        System.out.println("MySQL查到，返回" + stu);
                        ops.set(PREFIX + id, stu);
                        return stu;
                    }
                }else{
                    System.out.println("布隆过滤器判断id数据库不存在，直接返回");
                }
//                else {
//                    //MySQL没有数据,在Redis保存空对象
//                    System.out.println("MySQL没有数据");
//                    Student student = new Student();
//                    ops.set(PREFIX + id, student,5, TimeUnit.SECONDS);
//                }
            }
        }else {
            System.out.println("没有执行同步锁");
        }
        return stu;
    }
}
